/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package web.diva.client.pca.view;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.smartgwt.client.widgets.IButton;
import java.util.HashMap;
import web.diva.client.GreetingServiceAsync;
import web.diva.client.selectionmanager.ModularizedListener;
import web.diva.client.selectionmanager.Selection;
import web.diva.client.selectionmanager.SelectionManager;
import web.diva.shared.beans.PCAImageResult;

/**
 *
 * @author Yehia Farag
 * PCA plot container for pca-plot images
 */
public class PCAPlot extends ModularizedListener {

    private SelectionManager selectionManager;
    private boolean zoom = false;
    private boolean selectAll = false;
    private GreetingServiceAsync greetingService;
    private IButton resetPlotBtn;
    private boolean enable = true;
    private int[] currentDataSet;
    private int[] selectedRows;

    @Override
    public String toString() {
        return "PCAPlot";
    }

    @Override
    public void selectionChanged(Selection.TYPE type) {
        if (type == Selection.TYPE.OF_ROWS) {
            Selection sel = selectionManager.getSelectedRows(datasetId);
            if (sel != null && !zoom && !selectAll) {
                selectedRows = sel.getMembers();
                if (selectedRows != null && selectedRows.length != 0) {
                    updateSelection(selectedRows);
                }
            }
        }
    }
    private VerticalPanel layout;
    private VerticalPanel imgLayout;
    private HorizontalPanel buttonsLayout;
//    private PCAPoint[] selectionIndexMap;
    private Image chart;
    private HTML toolTip = new HTML();
    private double height = 290.0;
    private double width;

    public PCAPlot(final PCAImageResult results, SelectionManager selectionManager, GreetingServiceAsync greetingService) {

        this.greetingService = greetingService;
        this.classtype = 3;
        this.datasetId = results.getDatasetId();
        this.components.add(PCAPlot.this);
        this.selectionManager = selectionManager;
        this.selectionManager.addSelectionChangeListener(results.getDatasetId(), PCAPlot.this);
        layout = new VerticalPanel();
        if (290.0 < RootPanel.get("PCAChartResults").getOffsetHeight()) {
            height = RootPanel.get("PCAChartResults").getOffsetHeight() - 10;
        }
        layout.setHeight(height + "px");
        layout.setWidth("" + RootPanel.get("PCAChartResults").getOffsetWidth() + "px");
        layout.setBorderWidth(1);
        RootPanel.get("tooltip").add(toolTip);
        imgLayout = new VerticalPanel();

        imgLayout.setHeight((height - 25.0) + "px");
        imgLayout.setWidth(RootPanel.get("PCAChartResults").getOffsetWidth() + "px");

        buttonsLayout = new HorizontalPanel();
        buttonsLayout.setWidth("" + RootPanel.get("PCAChartResults").getOffsetWidth() + "px");
        buttonsLayout.setHeight("25px");

        width = RootPanel.get("PCAChartResults").getOffsetWidth();

        // Make a new check box, and select it by default.
        layout.add(imgLayout);
        CheckBox cb = new CheckBox("Zoom");
        resetPlotBtn = new IButton("Reset");
        resetPlotBtn.setTooltip("Reset the Plot");
        resetPlotBtn.setSize("40px", "20px");
        cb.setChecked(false);    // Hook up a handler to find out when it's clicked.
        cb.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                zoom = ((CheckBox) event.getSource()).isChecked();
                if (!zoom) {
//                    updateWithSelection();
                }
            }
        });

        buttonsLayout.add(cb);

        CheckBox cb2 = new CheckBox("Show All");
        cb2.setChecked(selectAll);    // Hook up a handler to find out when it's clicked.
        cb2.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                selectAll = ((CheckBox) event.getSource()).isChecked();
                if (!selectAll) {
                    updateWithSelection();
                } else {
                    updateSelection(null);
                }
            }
        });
        buttonsLayout.setBorderWidth(1);
        buttonsLayout.add(cb2);

        resetPlotBtn.disable();
        resetPlotBtn.addClickHandler(new com.smartgwt.client.widgets.events.ClickHandler() {

            @Override
            public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
                if (!zoom) {
                    resetPlotBtn.disable();
                    currentDataSet = null;
                    updateWithSelection();
                }
            }
        }
        );

        this.chart = new Image();
        chart.setHeight((height - 25.0) + "px");
        chart.setWidth(RootPanel.get("PCAChartResults").getOffsetWidth() + "px");
        imgLayout.add(chart);
        initChartImage();

        buttonsLayout.add(resetPlotBtn);

        buttonsLayout.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
        buttonsLayout.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);

        layout.add(buttonsLayout);
        layout.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
        layout.setVerticalAlignment(HasVerticalAlignment.ALIGN_BOTTOM);
        updateWithSelection();

    }

    private void updateWithSelection() {
        Selection sel = selectionManager.getSelectedRows(datasetId);
        if (sel != null) {
            selectedRows = sel.getMembers();
            this.updateSelection(selectedRows);
        } else {
            this.updateSelection(null);
        }

    }

    /**
     * This method is responsible for mapping the  image selection coordinates to omics data indexes
    */
    private void getSelection(double maxX, double minX, double maxY, double minY) {
        greetingService.getPCASelection(maxX, minX, maxY, minY, new AsyncCallback<int[]>() {
            @Override
            public void onFailure(Throwable caught) {
                RootPanel.get("loaderImage").setVisible(false);
            }

            @Override
            public void onSuccess(int[] result) {
                if (result != null && !zoom) {
                    updateSelectedList(result);
                } else if (result != null && zoom) {
                    updateSelection(result);

                }
            }
        });
    }

    private void updateSelectedList(int[] selIndex) {
        Selection selection = new Selection(Selection.TYPE.OF_ROWS, selIndex);
        selectionManager.setSelectedRows(datasetId, selection);
    }

    public VerticalPanel getScatterPlotLayout() {
        return layout;
    }

    private void updateSelection(int[] selection) {
        if (enable) {
            if (zoom) {
                currentDataSet = selection;
            }
            greetingService.updatePCASelection(datasetId, currentDataSet, selectedRows, zoom, selectAll, width, (height - 25.0), new AsyncCallback<PCAImageResult>() {
                @Override
                public void onFailure(Throwable caught) {
                    RootPanel.get("loaderImage").setVisible(false);
                }

                @Override
                public void onSuccess(PCAImageResult result) {

                    chart.setUrl(result.getImgString());
//                    selectionIndexMap = result.getIndexeMap();
                    tooltips = result.getXyName();
                    if (zoom) {
                        resetPlotBtn.enable();
                    }
                    RootPanel.get("loaderImage").setVisible(false);
                }
            });

        }
    }

    private MouseMoveHandler mouseMoveHandler;
    private MouseOutHandler mouseOutHandler;
    private MouseUpHandler mouseUpHandler;
    private MouseDownHandler mouseDownHandler;
    private HandlerRegistration moveRegHandler;
    private HandlerRegistration outRegHandler;
    private HandlerRegistration upRegHandler;
    private HandlerRegistration downRegHandler;
    private int startX;
    private int endX;
    private int startY;
    private int endY;
    private HashMap<String, String> tooltips;
    
    /**
     * This method is responsible for initializing image information
     */
    private void initChartImage() {

        if (mouseMoveHandler == null) {

            mouseMoveHandler = new MouseMoveHandler() {
                @Override
                public void onMouseMove(MouseMoveEvent event) {
                    double yi = event.getY();
                    double xi = event.getX();

                    int x = (int) xi;
                    int y = (int) yi;
                    String key = x + "," + y;
                    String key1 = (x + 1) + "," + y;
                    String key2 = (x - 1) + "," + y;
                    String key3 = x + "," + (y + 1);
                    String key4 = x + "," + (y - 1);
                    if (tooltips.containsKey(key)) {
                        updateToolTip(tooltips.get(key));

                    } else if (tooltips.containsKey(key1)) {
                        updateToolTip(tooltips.get(key1));
                    } else if (tooltips.containsKey(key2)) {
                        updateToolTip(tooltips.get(key2));
                    } else if (tooltips.containsKey(key3)) {
                        updateToolTip(tooltips.get(key3));
                    } else if (tooltips.containsKey(key4)) {
                        updateToolTip(tooltips.get(key4));
                    } else {
                        toolTip.setText("");
                        toolTip.setVisible(false);
                    }
                }
            };

        }
        if (mouseOutHandler == null) {
            mouseOutHandler = new MouseOutHandler() {
                @Override
                public void onMouseOut(MouseOutEvent event) {
                    toolTip.setText("");
                    toolTip.setVisible(false);
                }
            };
        }
        if (moveRegHandler != null) {
            moveRegHandler.removeHandler();
        }
        if (outRegHandler != null) {
            outRegHandler.removeHandler();
        }

        moveRegHandler = chart.addMouseMoveHandler(mouseMoveHandler);
        outRegHandler = this.chart.addMouseOutHandler(mouseOutHandler);
        if (mouseUpHandler == null) {
            mouseUpHandler = new MouseUpHandler() {

                @Override
                public void onMouseUp(MouseUpEvent event) {
                    endX = event.getX();
                    endY = event.getY();
                    //update 
                    getSelection(endX, startX, endY, startY);

                }
            };
        }
        if (upRegHandler != null) {
            upRegHandler.removeHandler();
        }
        upRegHandler = chart.addMouseUpHandler(mouseUpHandler);

        if (mouseDownHandler == null) {
            mouseDownHandler = new MouseDownHandler() {
                @Override
                public void onMouseDown(MouseDownEvent event) {
                    startX = event.getX();
                    startY = event.getY();
                    event.preventDefault();

                }
            };
        }
        if (downRegHandler != null) {
            downRegHandler.removeHandler();
        }
        downRegHandler = chart.addMouseDownHandler(mouseDownHandler);

    }

    private void updateToolTip(String lable) {
        String nString = "";
        if (lable.length() >= 30) {
            String row = "";
            for (String str : lable.split(",")) {
                nString = nString + str + ",";
                row = row + str + ",";
                if (row.length() >= 30) {
                    nString = nString + "<br/>";
                    row = "";
                }

            }

        } else {
            nString = lable;
        }

        toolTip.setHTML("<p style='height:55px;font-weight: bold; color:white;font-size: 10px;background: #819FF7; border-style:double;'>" + nString + "</p>");
        toolTip.setVisible(true);
    }

    public void enable(boolean enabel) {
        this.enable = enabel;

    }

     /**
     * This method is responsible for removing all references on removing components
     */
    @Override
    public void remove() {
        selectionManager = null;
        mouseMoveHandler = null;
        mouseOutHandler = null;
        mouseUpHandler = null;
        mouseDownHandler = null;
        moveRegHandler = null;
        outRegHandler = null;
        upRegHandler = null;
        downRegHandler = null;
        layout = null;
        imgLayout = null;
        buttonsLayout = null;
//        selectionIndexMap = null;
        chart = null;
        toolTip = null;

        greetingService = null;
        resetPlotBtn = null;
        currentDataSet = null;
        selectedRows = null;
    }

}
